package br.com.ac.fatureweb.integration.utilitary;

import java.text.NumberFormat;
import java.util.Locale;

import br.com.ac.fatureweb.integration.model.CodeBar;

public final class MakeCodeBar {

	/*
	 * Receber a string numérica de 44 caracteres e dividi-la em pares, formando
	 * 22 pares. A cada 2 caracteres numéricos identificar o seu valor na tabela
	 * abaixo.
	 */
	private static final String valoresAlfa[] = { "nnWWn", "NnwwN", "nNwwN",
			"NNwwn", "nnWwN", "NnWwn", "nNWwn", "nnwWN", "NnwWn", "nNwWn",
			"wnNNw", "WnnnW", "wNnnW", "WNnnw", "wnNnW", "WnNnw", "wNNnw",
			"wnnNW", "WnnNw", "wNnNw", "nwNNw", "NwnnW", "nWnnW", "NWnnw",
			"nwNnW", "NwNnw", "nWNnw", "nwnNW", "NwnNw", "nWnNw", "wwNNn",
			"WwnnN", "wWnnN", "WWnnn", "wwNnN", "WwNnn", "wWNnn", "wwnNN",
			"WwnNn", "wWnNn", "nnWNw", "NnwnW", "nNwnW", "NNwnw", "nnWnW",
			"NnWnw", "nNWnw", "nnwNW", "NnwNw", "nNwNw", "wnWNn", "WnwnN",
			"wNwnN", "WNwnn", "wnWnN", "WnWnn", "wNWnn", "wnwNN", "WnwNn",
			"wNwNn", "nwWNn", "NwwnN", "nWwnN", "NWwnn", "nwWnN", "NwWnn",
			"nWWnn", "nwwNN", "NwwNn", "nWwNn", "nnNWw", "NnnwW", "nNnwW",
			"NNnww", "nnNwW", "NnNww", "nNNww", "nnnWW", "NnnWw", "nNnWw",
			"wnNWn", "WnnwN", "wNnwN", "WNnwn", "wnNwN", "WnNwn", "wNNwn",
			"wnnWN", "WnnWn", "wNnWn", "nwNWn", "NwnwN", "nWnwN", "NWnwn",
			"nwNwN", "NwNwn", "nWNwn", "nwnWN", "NwnWn", "nWnWn" };

	/**
	 * 
	 */
	private MakeCodeBar() {
		super();
	}

	/**
	 * <p>
	 * Gerar Código de Barra.
	 * </p>
	 *
	 * <p>
	 * - O código de barras é do tipo 2 de 5 intercalado, ou seja, 2 de 5
	 * significa que 5 barras definem 1 caracter sendo que duas delas são barras
	 * largas. Intercalado significa que o espaço entre as barras também tem
	 * significado.<br/>
	 * - O tamanho total do campo do código de barras é de 48 posições com os
	 * dígitos verificadores, sendo 44 para conteúdo dos dados, mais quatro
	 * destinados ao dígito verificador. - O código de barras será composto por
	 * 4 blocos de 11 posições acrescidos de 1 dígito verificador para cada
	 * bloco. Os dígitos verificadores não estarão representados na string do
	 * código de barras e serão calculados de acordo com o módulo 10.
	 *
	 * Exemplo de blocos da string numérica do código de barras com dígito
	 * verificador: Bloco1:|8|2|6|5|0|0|0|0|0|3|3|DV1:4,
	 * Bloco2:|1|2|2|0|0|0|0|9|0|0|3|DV2:7 Bloco3:|3|0|6|8|0|0|1|2|0|0|8|DV3:2,
	 * Bloco4:|0|0|0|0|0|0|0|0|0|0|1|DV4:8
	 * </p>
	 *
	 * <p>
	 * Exemplo de string alfa de 110 caracteres concatenada:
	 * wNnwNNwWnnnnWWnnnWWnNNwwnWwnnNnWnnWnnWWnnnWWnnwNWnNNwwnwwNNnNwwNnnnWWnwNnnWnnWWnwnNWnnnWWnnnWWnnnWWnnnWWnNnwwN
	 * </p>
	 *
	 * @return O Sistema retorna o Código de Barras pronto contendo as strings
	 *         numéricas, o dígito verificador de cada string e a string alfa do
	 *         código de barra.
	 */
	public static CodeBar calc(String codeBar, Double totalBilling) {

		String primeiraParte = codeBar.substring(0, 3);

		String segundaParte = getValueFormat(totalBilling)
				+ codeBar.substring(15, 44);

		String codigoBarra = primeiraParte + segundaParte;

		final String digitoVerificador4P = Mod10.getDV(codigoBarra);

		final String codigoBarraFinal = primeiraParte + digitoVerificador4P
				+ segundaParte;

		final String bloco1 = codigoBarraFinal.substring(0, 11);
		final String bloco2 = codigoBarraFinal.substring(11, 22);
		final String bloco3 = codigoBarraFinal.substring(22, 33);
		final String bloco4 = codigoBarraFinal.substring(33, 44);

		final Character digitoVerificador1 = Mod10.getDV(bloco1).charAt(0);
		final Character digitoVerificador2 = Mod10.getDV(bloco2).charAt(0);
		final Character digitoVerificador3 = Mod10.getDV(bloco3).charAt(0);
		final Character digitoVerificador4 = Mod10.getDV(bloco4).charAt(0);

		final CodeBar codigoBarraVO = new CodeBar();

		// Seta o 1º bloco do código de barras
		codigoBarraVO.setDscCodigoBarra1(bloco1);

		// Seta o 2º bloco do código de barras
		codigoBarraVO.setDscCodigoBarra2(bloco2);

		// Seta o 3º bloco do código de barras
		codigoBarraVO.setDscCodigoBarra3(bloco3);

		// Seta o 4º bloco do código de barras
		codigoBarraVO.setDscCodigoBarra4(bloco4);

		/*
		 * 4º Passo: - Passar a string de 11 caracteres da posição 1 até 11 e
		 * retornar o digito verificador da string informada através do cálculo
		 * do módulo 11.
		 */
		codigoBarraVO.setNumDigitoCodigoBarra1(digitoVerificador1);

		/*
		 * 5º Passo: - Passar a string de 11 caracteres da posição 12 até 22 e
		 * retornar o digito verificador da string informada através do cálculo
		 * do módulo 11.
		 */
		codigoBarraVO.setNumDigitoCodigoBarra2(digitoVerificador2);

		/*
		 * 6º Passo: - Passar a string de 11 caracteres da posição 23 até 33 e
		 * retornar o digito verificador da string informada através do cálculo
		 * do módulo 11.
		 */
		codigoBarraVO.setNumDigitoCodigoBarra3(digitoVerificador3);

		/*
		 * 7º Passo: - Passar a string de 11 caracteres da posição 34 até 44 e
		 * retornar o digito verificador da string informada através do cálculo
		 * do módulo 11.
		 */
		codigoBarraVO.setNumDigitoCodigoBarra4(digitoVerificador4);

		codigoBarraVO.setAlfaCodigoBarra(returnValueAlfa(codigoBarraFinal));

		return codigoBarraVO;
	}

	/**
	 * Recebe o valor da fatura preenchendo com zeros a esquerda até atingir o
	 * tamanho especificado.
	 */
	private static String getValueFormat(final Double totalBilling) {

		final NumberFormat instance = NumberFormat.getInstance(new Locale("pt",
				"br"));

		instance.setGroupingUsed(false);
		instance.setMaximumFractionDigits(2);
		instance.setMinimumFractionDigits(2);
		instance.setMinimumIntegerDigits(9);
		instance.setMaximumIntegerDigits(9);

		final String valorFatura = instance.format(totalBilling);

		final int i = valorFatura.indexOf(',');

		final String valorFaturaAlterado = valorFatura.substring(0, i)
				+ valorFatura.substring(i + 1, valorFatura.length());

		return valorFaturaAlterado;
	}

	/*
	 * Gerar string alfa de 110 caracteres conforme padrão I25
	 */
	private static String returnValueAlfa(final String sequencia) {
		/*
		 * Receber a string numérica de 44 caracteres e dividi-la em pares,
		 * formando 22 pares. A cada 2 caracteres numéricos identificar o seu
		 * valor .Para cada par: Concatenar e acumular o valor alfa em uma
		 * string até que se forme uma string de 110 caracteres.
		 */
		String sequenciaAlfa = "";

		for (int i = 0; i < 22; i++) {
			sequenciaAlfa = sequenciaAlfa
					+ valoresAlfa[Integer.parseInt(String.valueOf(sequencia
							.charAt(2 * i))
							+ String.valueOf(sequencia.charAt(2 * i + 1)))];
		}

		return "<" + sequenciaAlfa + ">";
	}

}
